#pragma once
#include "DSP.h"
#include "FastSin.h"
#include "RingBuffer.h"
#include "lang/Math.h"
namespace yzrilyzr_dsp{
	typedef double(*OscFunc)(double x);
	inline static double square(double x){
		return RingBufferUtil::mod1(x) > 0.5?1.0:-1.0;
	}
	inline static double saw(double x){
		return RingBufferUtil::mod1(x)*2.0-1.0;
	}
	inline static double tri(double x){
		x=RingBufferUtil::mod1(x);
		return x > 0.5?((1 -x) * 4 - 1):(x * 4 - 1);
	}
	ECLASS(Oscillator, public DSP){
	protected:
	u_phase phase=0;
	u_phase deltaPhase=0;
	OscFunc osc=nullptr;
	public:
	u_freq freq=0;
	u_phase initPhase=0;
	Oscillator();
	Oscillator(u_freq freq, OscFunc func) :freq(freq), osc(func){}
	Oscillator(u_freq freq, OscFunc func, u_phase initPhase) :freq(freq), osc(func), initPhase(initPhase),phase(initPhase){}
	void init(u_sample_rate sampleRate)override{
		this->deltaPhase=freq / sampleRate;
	}
	u_sample procDsp(u_sample v)override{
		phase+=deltaPhase;
		return osc(phase);
	}
	void resetMemory()override{
		phase=initPhase;
	}
	yzrilyzr_lang::String toString()const override;
	std::shared_ptr<DSP> cloneDSP()override{
		return std::make_shared<Oscillator>(freq, osc, initPhase);
	}
	void setInitPhase(u_normal_01 phase1){
		this->initPhase=phase1;
		this->phase=phase1;
	}
	void cloneParam(DSP * obj1)override{
		if(auto other=dynamic_cast<Oscillator *>(obj1)){
			freq=other->freq;
			osc=other->osc;
			initPhase=other->initPhase;
		}
	}
	};
	ECLASS(SineOscillator, public Oscillator){
	public:
	SineOscillator(u_freq freq) :Oscillator(freq, nullptr){}
	SineOscillator(u_freq freq, u_phase initPhase) :Oscillator(freq, nullptr, initPhase){}
	u_sample procDsp(u_sample v)override{
		phase+=deltaPhase;
		return fast_sin(phase* yzrilyzr_lang::Math::TAU, freq);
	}
	std::shared_ptr<DSP> cloneDSP()override{
		return std::make_shared<SineOscillator>(freq, initPhase);
	}
	};
	ECLASS(SquareOscillator, public Oscillator){		
	public:
		SquareOscillator(u_freq freq) :Oscillator(freq, square){}
		SquareOscillator(u_freq freq, u_phase initPhase) :Oscillator(freq, square, initPhase){}
		std::shared_ptr<DSP> cloneDSP()override{
			return std::make_shared<SquareOscillator>(freq, initPhase);
		}
	};
	ECLASS(SawOscillator, public Oscillator){		
	public:
	SawOscillator(u_freq freq) :Oscillator(freq, saw){}
	SawOscillator(u_freq freq, u_phase initPhase) :Oscillator(freq, saw, initPhase){}
	std::shared_ptr<DSP> cloneDSP()override{
		return std::make_shared<SawOscillator>(freq, initPhase);
	}
	};
	ECLASS(TriOscillator, public Oscillator){		
	public:
	TriOscillator(u_freq freq) :Oscillator(freq, tri){}
	TriOscillator(u_freq freq, u_phase initPhase) :Oscillator(freq, tri, initPhase){}
	std::shared_ptr<DSP> cloneDSP()override{
		return std::make_shared<TriOscillator>(freq, initPhase);
	}
	};
}